﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Drawing;
using System.Security.Permissions;

using Elegant.Ui;
using iPdf.Properties;

namespace iPdf
{
    partial class MainForm: Form
    {
        #region Methods

        /// <summary>
        /// return the page of the ribbon by its name
        /// </summary>
        /// <param name="pageName"></param>
        /// <returns></returns>
        public TataRibbonPage GetPageByName(string pageName)
        {
            if (string.IsNullOrEmpty(pageName))
            {
                return null;
            }

            foreach (RibbonTabPage page in Ribbon.TabPages)
            {
                if (page.Name == pageName)
                {
                    return (TataRibbonPage)page;
                }
            }

            return null;
        }

        /// <summary>
        /// switch to the specified page
        /// </summary>
        /// <param name="page"></param>
        public void SwitchToPage(RibbonTabPage page)
        {
            if (page != Ribbon.CurrentTabPage)
            {
                Ribbon.CurrentTabPage = page;
            }
        }

        private delegate void ProcessEventConsumer(ProcessItemEventArgs e);
        public void AddLoadingCircle(ProcessItemEventArgs e)
        {
            Grid.AddLoadingCircle(e.Index);
            UpdateStatusBar("Processing");
        }

        private void Actor_ItemStarted(object sender, ProcessItemEventArgs e)
        {
            int index = e.Index;
            
            if (this.InvokeRequired)
            {
                this.Invoke(new ProcessEventConsumer(AddLoadingCircle), new object[]{e});
            }
            else
            {
                AddLoadingCircle(e);
            }
        }

        private void RemoveLoadingCircle(ProcessItemEventArgs e)
        {
            Grid.RemoveLoadingCircle(e);
            if (e.Index == Grid.RowsCount - 1)
            {
                UpdateStatusBar("Finishing");
            }
        }

        private void Actor_ItemFinished(object sender, ProcessItemEventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new ProcessEventConsumer(RemoveLoadingCircle), new object[] { e });
            }
            else
            {
                RemoveLoadingCircle(e);
            }
        }


        public void ActionDone(ProcessItemEventArgs e)
        {
            ActionReport report = e.Report;
            string message = ActionCancelled == true ?
                global::iPdf.Properties.Resources.ActionCancelled :
                global::iPdf.Properties.Resources.ActionDone;

            string actionReport = global::iPdf.Properties.Resources.ActionReport;
            actionReport = actionReport.Replace("{done}", report.DoneItemsCount.ToString());
            actionReport = actionReport.Replace("{error}", report.ErrorItemsCount.ToString());
            actionReport = actionReport.Replace("{undone}", report.UndoneItemsCount.ToString());

            message += actionReport;

            if (report.ErrorItemsCount > 0)
            {
                message += global::iPdf.Properties.Resources.ErrorsOccurred;
            }

            ShowNotification(message);

            Status = WorkStatus.Idle;
            cancelAction = false;
            UpdateRibbon();
            UpdateGrid();
            UpdateNotifyIconMenu();
            UpdateStatusBar("Idle");
        }

        private void Actor_AllItemsFinished(object sender, ProcessItemEventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new ProcessEventConsumer(ActionDone), new object[]{e});
            }
            else
            {
                ActionDone(e);
            }
        }

        private void OnItemFound(string item)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new ItemRetrievor.FoundItem(AddItemToGrid), new object[] { item });
            }
            else
            {
                AddItemToGrid(item);
            }
        }

        private void OnFindingComplete(string[] items)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new ItemRetrievor.FindingComplete(AddItemsToGrid), items);
            }
            else
            {
                AddItemsToGrid(items);
            }
        }

        private void AddItemToGrid(string item)
        {
            if (!Busy)
            {
                Grid.AddItem(item);
            }
        }

        public void AddItemsToGrid(string[] items)
        {
            if (!Busy)
            {
                Grid.AddItems(items);
                UpdateRibbon();
            }
        }

        private void AddItems(Elegant.Ui.Command sender)
        {
            ItemRetrievor retrievor = new ItemRetrievor(Format,
                    OnFindingComplete,
                    OnItemFound);
            if (sender == ApplicationCommands.AddFiles)
            {
                retrievor.RetrieveFiles();
            }
            else
            {
                retrievor.RetrieveFolder(SearchOption);
            }
        }

        public void EnableRibbon(bool enable)
        {
            if (enable == false)
            {
                Helper.EnableControl(Ribbon, false);
            }
            else
            {
                Helper.EnableControl(Ribbon, true);
                UpdateRibbon();
            }
        }


        public void UpdateGrid()
        {
            Grid.UpdateCells();
        }

        public void UpdateActionGroup()
        {
            if (currentPage.ReadyToAct == true && !Busy)
            {
                Helper.EnableControl(ActionGroup, true);
                Start.Enabled = true;
                Stop.Enabled = false;
            }
            else
            {
                if (!Busy)
                {
                    Helper.EnableControl(ActionGroup, false);
                }
                else
                {
                    Helper.EnableControl(Stop, true);
                }
            }
        }

        private void EnableCommonRibbonGroups(bool enable)
        {
            Helper.EnableControl(AddGroup, enable);
            Helper.EnableControl(MoveGroup, enable);
            Helper.EnableControl(OptionsGroup, enable);
            Helper.EnableControl(ActionGroup, enable);
        }

        public void UpdateCommonRibbonControls()
        {
            if (Busy)
            {
                Helper.EnableControl(CurrentPage.Parent, false, false);
                Helper.EnableControl(Stop, true);
            }
            else if (Previewer.Busy)
            {
                Helper.EnableControl(currentPage.Parent, false, false);
            }
            else if (Grid.HasItems)
            {
                Helper.EnableControl(Ribbon, true);
                currentPage.UpdatePageOnlyControls();
                UpdateMoveGroup();
                UpdateOptionGroup();
                UpdateActionGroup();
            }
            else
            {
                Helper.EnableControl(Ribbon, true, true);
                Helper.EnableControl(Ribbon.CurrentTabPage, false, false);
                Helper.EnableControl(AddGroup, true);
            }

            UpdateOrbMenu();
        }

        public void UpdateNotifyIconMenu()
        {
            ExitToolStripMenuItem.Enabled = !Busy;
        }

        public void UpdateOrbMenu()
        {
            bool orbEnabled = !this.Busy && !this.previewer.Busy;
            foreach (Elegant.Ui.Control item in OrbMenu.Items)
            {
                item.Enabled = orbEnabled;
            }

            this.RecentFiles.Enabled = orbEnabled;
        }

        public void UpdateMoveGroup()
        {
            if (Busy)
            {
                Helper.EnableControl(MoveGroup, false);
                return;
            }

            Helper.EnableControl(MoveUp, 
                    currentPage.OrderMatters && Grid.CanSelectionMoveUp);
            Helper.EnableControl(MoveDown,
                    currentPage.OrderMatters &&  Grid.CanSelectionMoveDown);
            Helper.EnableControl(RemoveSelection, Grid.SelectionExists);
            Helper.EnableControl(RemoveAll, Grid.RowsCount > 1);
        }

        public void UpdateOptionGroup()
        {
            if (currentPage.HasOptionGroup)
            {
                Helper.EnableControl(SetOutputFolder,
                            currentPage.IsColumnVisible(Global.Grid.Destination));
                PdfLets = currentPage.PdfLets;
            }
        }

        public void UpdateRibbon()
        {
            UpdateCommonRibbonControls();
            CurrentPage.UpdatePage();
        }

        private void UpdateStatusBar(string action)
        {
            ActionInfo.Text = action;
        }

        protected override void WndProc(ref Message message)
        {
            base.WndProc(ref message);
            if (message.Msg == WinApi.WM_SHOWFIRSTINSTANCE)
            {
                ShowMainWindow(true);
            }
        }

        private void UpdatePrinterStatusInfo()
        {
            string printerBusyInfo = global::iPdf.Properties.Resources.PrinterBusyInfo;
            string printerIdleInfo = global::iPdf.Properties.Resources.PrinterIdleInfo;

            if (IsPdfCreatorBusy)
            {
                if (PrinterStatusInfo.Text == printerIdleInfo)
                {
                    PrinterStatusInfo.Text = printerBusyInfo;
                    PrinterStatus.Pressed = true;
                }
            }
            else
            {
                if (PrinterStatusInfo.Text != printerIdleInfo)
                {
                    PrinterStatusInfo.Text = printerIdleInfo;
                    PrinterStatus.Pressed = false;
                }
            }
        }

        public void UpdatePrintingRelatedControls()
        {
            if (loaded && !tabPageChanging)
            {
                UpdatePrinterStatusInfo();
                if (!ItemRetrievor.Busy && !Busy && !this.previewer.Busy && currentPage.PrinterDependent)
                {
                    bool canDoAction = !PdfCreator.Running && currentPage.ReadyToAct && !Busy;
                    if (canDoAction != Start.Enabled)
                    {
                        Helper.EnableControl(Start, canDoAction);
                    }
                }
            }
        }

        private delegate void Notifier(string title, string text);

        public void ShowNotification(string text)
        {
            ShowNotification(text, false);
        }

        public void ShowNotification(string text, bool contentAsLink)
        {
            if (this.InvokeRequired)
            {
                object[] paras = new object[] { Global.ApplicationName, text, contentAsLink};
                this.Invoke(new Notifier(Helper.ShowNotification), paras);
            }
            else
            {
                Helper.ShowNotification(Global.ApplicationName, text, contentAsLink);
            }
        }

        private delegate void ErrorReporter(TataException ex);

        public void ShowError(TataException ex)
        {
            if (this.InvokeRequired)
            {
                object[] paras = new object[] { ex };
                this.Invoke(new ErrorReporter(Helper.ShowError), paras);
            }
            else
            {
                Helper.ShowError(ex);
            }
        }

        public void ImportQueuedTask()
        {
            if (!loaded)
            {
                return;
            }

            if (!Busy)
            {
                Task task = TaskQueue.GetTask();
                if (task != null)
                {
                    TataRibbonPage page = GetPageByName(task.Page);
                    SwitchToPage(page);
                    Grid.RemoveAll();
                    AddItemsToGrid(task.Items);
                    if (Grid.HasItems && IsRunningInBackground)
                    {
                        ShowMainWindow(true);
                        Status = WorkStatus.TaskImported;
                    }

                    ShowNotification(global::iPdf.Properties.Resources.TaskImported);
                }
            }
            else
            {
                //Not idle, we check if there is a task that is has been just queued
                if (TaskQueue.JustQueued)
                {
                    TaskQueue.JustQueued = false;
                    ShowNotification(global::iPdf.Properties.Resources.TaskQueued);
                }
            }
        }


        public void LoadCommonControls()
        {
            currentPage.SuspendLayout();
            currentPage.Controls.Add(AddGroup);
            currentPage.Controls.Add(MoveGroup);
            if (currentPage.HasOptionGroup)
            {
                currentPage.Controls.Add(OptionsGroup);
            }

            currentPage.Controls.Add(ActionGroup);
            currentPage.Controls.SetChildIndex(AddGroup, 0);
            currentPage.Controls.SetChildIndex(MoveGroup, 1);
            if (currentPage.HasOptionGroup)
            {
                currentPage.Controls.SetChildIndex(OptionsGroup, 2);
            }
            currentPage.ResumeLayout(false);
            currentPage.PerformLayout();
        }

        private void Save()
        {
            PersistentStateManager.SaveToIsolatedStorageForDomain();
            RecentItems.Save();
            SetOutputFolder.Save();
            TataRibbonPage.SaveCertificates();
            foreach (TataRibbonPage page in TabPages)
            {
                page.SavePageOnlyData();
            }
        }

        private void ShowMainWindow(bool show)
        {
            if (show)
            {
                if (!IsRunningInBackground)
                {
                    return;
                }

                this.Show();
                this.WindowState = oldWindowState;
                
                if (this.ShowInTaskbar == false)
                {
                    this.ShowInTaskbar = true;
                }

                if (!IsForegroundWindow)
                {
                    WinApi.ShowToFront(this.Text);
                }
            }
            else
            {
                if (this.ShowInTaskbar == true)
                {
                    if (this.OrbMenu.Visible == true)
                    {
                        this.OrbMenu.Hide();
                    }
                    this.Hide();
                    this.ShowInTaskbar = false;
                }
            }
        }

        private void AdjustClientControl(System.Windows.Forms.Control clientControl)
        {
            if (clientControl == null)
            {
                return;
            }

            int newVerticalLocation = this.Ribbon.Height;
            int adjustment = newVerticalLocation - clientControl.Location.Y;

            Helper.AdjustSizeAndLocationByOffset(clientControl, 0, 0, adjustment, -adjustment);
        }

        private void FitClientControl(System.Windows.Forms.Control clientControl)
        {
            if (clientControl == null)
            {
                return;
            }

            int preferrableWidth = clientControl == this.SessionsPanel ? 
                                       clientControl.Width :(this.Ribbon.Width - clientControl.Location.X);
            int preferrableHeight = this.StatusBar.Location.Y - clientControl.Location.Y;

            if (preferrableWidth > 0 && preferrableHeight > 0)
            {
                clientControl.Size = new Size(preferrableWidth, preferrableHeight);
                AdjustClientControl(clientControl);
            }
        }

        private void FitClientControls()
        {
            FitClientControl(this.Grid);
            FitClientControl(this.SessionsPanel);
            FitClientControl(this.previewer);
        }

        private void ShowMinimizeNotification()
        {
            if (firstMinimize)
            {
                firstMinimize = false;
                ShowNotification(Global.ApplicationName + global::iPdf.Properties.Resources.RunningInSystemTray);
            }
        }

        private void InitializePreviewer()
        {
            this.previewer = new iPdf.Previewer();
            this.previewer.AutoSize = true;
            this.previewer.BackColor = System.Drawing.Color.LightSkyBlue;
            this.previewer.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.previewer.Location = new System.Drawing.Point(0, 154);
            this.previewer.Name = "previewer";
            this.previewer.Size = new System.Drawing.Size(572, 451);
            this.previewer.TabIndex = 3;
            this.previewer.Visible = false;

            this.Controls.Add(this.previewer);
        }

        //clean up the resources when unhandled exception happened
        public void Cleanup()
        {
            NotifyIcon.Visible = false;
        }

        public void ShowPageSize(float width, float height)
        {
            string sizeText = width == 0.0f || height == 0.0f? string.Empty : 
                                        (UnitConverter.PointsToInches(width).ToString() + 
                                        " X " + UnitConverter.PointsToInches(height).ToString() + " in");

            this.PageSize.Tag = new SizeF(width, height);

            this.PageSize.Text = sizeText;
        }

        private void UpdateSessionsPanel()
        {
            if (currentPage != null && currentPage.SessionEnabled == true)
            {
                this.SessionsPanel.Show();
            }
            else
            {
                this.SessionsPanel.Hide();
            }

            SessionsPanel_Resize(this.SessionsPanel, new EventArgs());
        }

        private void UpdatePageIntroInfo()
        {
            if (this.currentPage != null && !string.IsNullOrEmpty(this.currentPage.IntroInfo))
            {
                this.PageIntroInfo.Text = this.currentPage.IntroInfo;
            }
        }

        #endregion//Methods
    }
}
